package com.example.ucs_alg_node_manager.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.ucs_alg_node_manager.domain.*;
import com.example.ucs_alg_node_manager.dto.NodeDTO;
import com.example.ucs_alg_node_manager.dto.QueryDTO;
import com.example.ucs_alg_node_manager.service.*;
import com.example.ucs_alg_node_manager.mapper.NodeMapper;
import com.example.ucs_alg_node_manager.utils.RestTemplateUtil;
import com.example.ucs_alg_node_manager.utils.UcsPatterns;
import com.example.ucs_alg_node_manager.vo.NodeVO;
import com.example.ucs_alg_node_manager.vo.QueryVO;
import com.example.ucs_alg_node_manager.vo.ReturnVO;
import com.example.ucs_alg_node_manager.vo.SystemStatus;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
* @author 31586
* @description 针对表【ucs_node】的数据库操作Service实现
* @createDate 2024-08-29 16:05:15
*/
@Service
public class NodeServiceImpl extends ServiceImpl<NodeMapper, Node>
    implements NodeService {

    @Resource
    private RestTemplateUtil restTemplateUtil;

    @Resource
    private AssembleService assembleService;

    @Resource
    private AlgService algService;

    @Resource
    private TaskService taskService;

    @Resource
    private ResultService resultService;

    @Resource
    private UserService userService;

    @Override
    public ReturnVO getNodes(QueryDTO dto) {
        IPage<Node> page = new Page<>(dto.getCurrent(), 5);
        page = page(page, Wrappers.<Node>lambdaQuery().eq(Node::getUserId, dto.getUserId()));
        List<NodeVO> list = new ArrayList<>();
        for (Node node : page.getRecords()) {
            NodeVO vo = BeanUtil.copyProperties(node, NodeVO.class);
            if (!"stopping".equals(vo.getStatus())) {
                SystemStatus<String> result = restTemplateUtil.getWithoutParams(UcsPatterns.ABOUT_URL);
                if("ok".equals(result.getCode())){
                    vo.setStatus("running");
                }else {
                    vo.setStatus("error");
                }
            }
            list.add(vo);
        }
        QueryVO<NodeVO> queryVO = new QueryVO<>();
        queryVO.setList(list);
        queryVO.setTotal(page.getTotal());
        return ReturnVO.ok(queryVO).message("查询成功");
    }

    @Override
    public ReturnVO getNodeByName(String name) {
        Node node = getOne(Wrappers.<Node>lambdaQuery().eq(Node::getName, name));
        if (!Optional.ofNullable(node).isPresent()) {
            return ReturnVO.fail().message("节点信息不存在");
        }

        SystemStatus<Map<String, Object>> result = restTemplateUtil.getWithoutParams(UcsPatterns.STAT_URL);

        // 设置系统负载数据
        node.setCpu(result.getMsg().get("cpu").toString());
        node.setGpu(result.getMsg().get("gpu").toString());
        node.setMen(result.getMsg().get("mem").toString());

        List<Assemble> assembles = assembleService.list(Wrappers.<Assemble>lambdaQuery().eq(Assemble::getType, "node")
                .eq(Assemble::getTypeId, node.getId()));
        if(assembles.size() >0) {
            node.setSource(assembles.get(0).getValue());
        }else {
            node.setSource("暂无数据源信息");
        }
        return ReturnVO.ok(node).message("查询成功");
    }

    @Override
    public ReturnVO addNode(NodeDTO dto) {
        System.out.println(dto);
        Integer userId = dto.getUserId();
        if(userId==null||  userService.getById(userId)==null) {
            return ReturnVO.fail().message("用户信息不存在");
        }

        Node node = getOne(Wrappers.<Node>lambdaQuery().eq(Node::getName, dto.getName()));
        if (Optional.ofNullable(node).isPresent()) {
            return ReturnVO.fail().message("节点信息已经存在");
        }
        node = BeanUtil.copyProperties(dto, Node.class);
        node.setStatus("running");
        String addr = node.getAddr();
        if (!UcsPatterns.isValidUrl(addr)){
            return ReturnVO.fail().message("非法节点地址");
        }
        String url = UcsPatterns.getBaseURL(addr);
        node.setAddr(url);

        save(node);

        // 同步生成算法配置信息
        Alg alg = new Alg();
        alg.setNodeId(node.getId());
        algService.save(alg);

        return ReturnVO.ok().message("节点信息添加成功");
    }

    @Override
    public ReturnVO delNode(Integer id) {
        Node node = getById(id);
        if (!Optional.ofNullable(node).isPresent()) {
            return ReturnVO.fail().message("节点信息不存在");
        }

        // 删除任务信息
        for (Task task : taskService.list(Wrappers.<Task>lambdaQuery().eq(Task::getNodeId, id))) {
            // 删除任务结果信息
            for (Result result : resultService.list(Wrappers.<Result>lambdaQuery().eq(Result::getTaskId, task.getId()))) {
                // 删除结果值信息
                assembleService.removeSources(result.getId(), "result");

                resultService.removeById(result);
            }
            // 删除任务数据源信息
            assembleService.removeSources(task.getId(), "task");

            taskService.removeById(task);
        }

        // 删除算法配置信息
        Alg alg = algService.getOne(Wrappers.<Alg>lambdaQuery().eq(Alg::getNodeId, id));
        // 删除算法数据源信息
        assembleService.removeSources(alg.getId(), "alg");

        // 删除节点数据源信息
        assembleService.removeSources(id, "node");


        removeById(id);
        return ReturnVO.ok().message("节点删除成功");
    }

    @Override
    public ReturnVO update(Node node) {
        String name = getById(node.getId()).getName();
        if(!name.equals(node.getName())){
            // 说明修改了节点名称
            if (Optional.ofNullable(getOne(Wrappers.<Node>lambdaQuery().eq(Node::getName, node.getName()))).isPresent()) {
                return ReturnVO.fail().message("节点名称已经使用");
            }
        }


        // 获取输出地址，将对应算法的输出地址配置成相同的
        String destAddr = node.getDestAddr();
        if (!UcsPatterns.isValidUrl(destAddr)) {
            return ReturnVO.fail().message("输出地址格式不合法");
        }

        String url = UcsPatterns.getBaseURL(destAddr);
        Alg alg = algService.getOne(Wrappers.<Alg>lambdaQuery().eq(Alg::getNodeId, node.getId()));
        node.setDestAddr(url);
        alg.setOutAddr(url);

        updateById(node);

        return ReturnVO.ok().message("节点信息修改成功");
    }

    @Override
    public ReturnVO setNode(Integer nodeId, String status) {
        Node node = getById(nodeId);
        if("run".equals(status)){
            // 启动指令
            try{
                SystemStatus<String> result = restTemplateUtil.post(UcsPatterns.RELOAD_URL, null);
                if ("ok".equals(result.getCode())) {
                    node.setStatus("running");
                    // 开始提交任务
                    taskService.submitTask(nodeId);
                    updateById(node);
                    return ReturnVO.ok().message("节点启动成功");
                }else {
                    node.setStatus("error");
                    updateById(node);
                    return ReturnVO.ok().message("节点启动失败");
                }

            }catch (Exception e){
                e.printStackTrace();
                return ReturnVO.fail().message("重启失败");
            }

        }else {
            // 停止指令
            node.setStatus("stopping");
            // 终止正在执行的任务
            taskService.stopTask(nodeId);
            updateById(node);
            return ReturnVO.ok().message("节点已停止");
        }

    }
}




